
package com.jf.cloud.order.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.jf.cloud.api.feign.SearchSpuFeignClient;
import com.jf.cloud.api.product.feign.ProductFeignClient;
import com.jf.cloud.api.product.feign.SpuFeignClient;
import com.jf.cloud.common.constant.Constant;
import com.jf.cloud.common.exception.LuckException;
import com.jf.cloud.common.i18n.I18nMessage;
import com.jf.cloud.common.order.vo.OrderCountVO;
import com.jf.cloud.common.product.constant.SupplierSpuType;
import com.jf.cloud.common.product.vo.SpuVO;
import com.jf.cloud.common.product.vo.search.SpuSearchVO;
import com.jf.cloud.common.response.ServerResponseEntity;
import com.jf.cloud.common.util.Arith;
import com.jf.cloud.common.util.DateUtils;
import com.jf.cloud.order.manager.MongoOrderManager;
import com.jf.cloud.order.manager.MongoOrderRefundManager;
import com.jf.cloud.order.mapper.OrderMapper;
import com.jf.cloud.order.mapper.OrderRefundMapper;
import com.jf.cloud.order.service.SupplierOrderStatisticsService;
import com.jf.cloud.order.vo.HotProductVO;
import com.jf.cloud.order.vo.OrderOverviewVO;
import com.jf.cloud.order.vo.OrderRefundStatisticsVO;
import com.jf.cloud.order.vo.SupplierOrderOverviewVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zz
 */
@Service
public class SupplierOrderStatisticsServiceImpl implements SupplierOrderStatisticsService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private MongoOrderManager mongoOrderManager;
    @Autowired
    private MongoOrderRefundManager mongoOrderRefundManager;
    @Autowired
    private OrderRefundMapper orderRefundMapper;
    @Autowired
    private SearchSpuFeignClient searchSpuFeignClient;
    @Autowired
    private SpuFeignClient spuFeignClient;
    @Autowired
    private ProductFeignClient productFeignClient;

    public static final Logger log = LoggerFactory.getLogger(SupplierOrderStatisticsServiceImpl.class);

    @Override
    public OrderCountVO getOrderCountOfStatusBySupplierId(Long supplierId) {
        OrderCountVO orderCount = mongoOrderManager.getOrderCountOfStatusBySupplierId(supplierId);
        orderCount.setRefund(mongoOrderRefundManager.getOrderCountBySupplierId(supplierId));
        return orderCount;
    }

    @Override
    public SupplierOrderOverviewVO getTodayInfoByHour(Long supplierId, Date startTime, Date endTime) {
        SupplierOrderOverviewVO supplierOrderOverviewVO = this.getOrderStatisticsByShopIdAndDateRange(supplierId, startTime, endTime);
        List<Integer> todayProdSoldCountList = this.listProdSoldCountByHour(supplierId, startTime, endTime);
        supplierOrderOverviewVO.setTodayProdSoldCountList(todayProdSoldCountList);

        List<Integer> yesterdayProdSoldCountList = this.listProdSoldCountByHour(supplierId, DateUtil.offsetDay(startTime, -1), DateUtil.offsetDay(endTime, -1));
        supplierOrderOverviewVO.setYesterdayProdSoldCountList(yesterdayProdSoldCountList);

        Integer todayShopNewUserCount = mongoOrderManager.getShopNewUsersBySupplierId(supplierId, startTime, null);
        supplierOrderOverviewVO.setTodayNewUserCount(todayShopNewUserCount);
        Integer yesterdayShopNewUserCount = mongoOrderManager.getShopNewUsersBySupplierId(supplierId, DateUtil.offsetDay(startTime, -1), DateUtil.offsetDay(endTime, -1));
        supplierOrderOverviewVO.setYesterdayNewUserCount(yesterdayShopNewUserCount);
        // 获取店铺近半个月的每天支付金额
        this.listPayActualAmount(supplierId, endTime, 15, supplierOrderOverviewVO);

        ServerResponseEntity<List<SpuVO>> spuVOListResponse = productFeignClient.listSpuIdsBySupplierIdAndSupplierSpuType(supplierId, null, SupplierSpuType.YES.value());
        if (spuVOListResponse.isFail()) {
            throw new LuckException(spuVOListResponse.getMsg());
        }
        if (CollUtil.isEmpty(spuVOListResponse.getData())) {
            supplierOrderOverviewVO.setTodayProdSoldNums(0);
        } else {
            supplierOrderOverviewVO.setTodayProdSoldNums(spuVOListResponse.getData().size());
        }
        // 今天上架的spuId
        ServerResponseEntity<List<SpuVO>> todaySpuVOListResponse = productFeignClient.listSpuIdsBySupplierIdAndSupplierSpuType(supplierId, DateUtil.format(DateUtil.beginOfDay(DateUtil.date()), "yyyy-MM-dd"), SupplierSpuType.YES.value());
        if (todaySpuVOListResponse.isFail()) {
            throw new LuckException(todaySpuVOListResponse.getMsg());
        }
        if (CollUtil.isEmpty(todaySpuVOListResponse.getData())) {
            supplierOrderOverviewVO.setYesterdayProdSoldNums(supplierOrderOverviewVO.getTodayProdSoldNums());
            return supplierOrderOverviewVO;
        }
        // 昨天在售商品数量 = 今天在售商品数量 - 今天上架商品数量
        supplierOrderOverviewVO.setYesterdayProdSoldNums(supplierOrderOverviewVO.getTodayProdSoldNums() - todaySpuVOListResponse.getData().size());
        return supplierOrderOverviewVO;
    }

    @Override
    public List<HotProductVO> listProdRankingByPayActual(Long supplierId, Integer dayCount, Integer limit) {
        Date endTime = DateUtil.endOfDay(DateUtil.date());
        Date startTime = this.getStartTime(endTime, dayCount);
        List<HotProductVO> hotProductVOList = mongoOrderManager.listHotProdRanking(supplierId, startTime, endTime, I18nMessage.getLang());
//        List<HotProductVO> hotProductVOList = orderMapper.listHotProdRanking(supplierId, startTime, endTime, I18nMessage.getLang());
        if (CollectionUtil.isEmpty(hotProductVOList)) {
            return hotProductVOList;
        }
        Map<Long, HotProductVO> hotProductVOMap = hotProductVOList.stream().collect(Collectors.toMap(HotProductVO::getSpuId, hotProductVO -> hotProductVO));

        // 先查询商家端独立发布的商品详情，用于后续获取对应的供应商商品信息 （此处不用es是因为es无法搜索已删除的商品，存在这样一种情况，商家端商品已删除，但其代销的供应商商品处于正常状态）
        ServerResponseEntity<List<SpuVO>> merchantSpuListResponse = productFeignClient.listSpuBySpuIds(new ArrayList<>(hotProductVOMap.keySet()));
        if (merchantSpuListResponse.isFail()) {
            throw new LuckException(merchantSpuListResponse.getMsg());
        }
        List<SpuVO> merchantSpuVOList = merchantSpuListResponse.getData();
        if (CollectionUtil.isEmpty(merchantSpuVOList)) {
            return hotProductVOList;
        }
        Map<Long, List<SpuVO>> consignmentProductMap = merchantSpuVOList.stream().collect(Collectors.groupingBy(SpuVO::getSupplierSpuId));

        // 根据被代销的供应商商品Id查询商品详情
        ServerResponseEntity<List<SpuSearchVO>> supplierSpuResponse = searchSpuFeignClient.listSpuBySpuIds(new ArrayList<>(consignmentProductMap.keySet()));
        if (supplierSpuResponse.isFail()) {
            throw new LuckException(supplierSpuResponse.getMsg());
        }
        List<SpuSearchVO> supplierSpuVOList = supplierSpuResponse.getData();

        List<HotProductVO> resultProdRankingList = new ArrayList<>();
        for (SpuSearchVO supplierSpu : supplierSpuVOList) {
            Long supplierSpuId = supplierSpu.getSpuId();
            HotProductVO hotProductVO = new HotProductVO();
            hotProductVO.setSpuId(supplierSpuId);
            hotProductVO.setPayAmount(0.0);
            hotProductVO.setOrderNums(0);
            hotProductVO.setProductNums(0);
            List<SpuVO> merchantSpuList = consignmentProductMap.get(supplierSpuId);
            if (CollUtil.isEmpty(merchantSpuList)){
                continue;
            }
            for (SpuVO merchantSpu : merchantSpuList) {
                hotProductVO.setPayAmount(hotProductVO.getPayAmount() + hotProductVOMap.get(merchantSpu.getSpuId()).getPayAmount());
                hotProductVO.setOrderNums(hotProductVO.getOrderNums() + hotProductVOMap.get(merchantSpu.getSpuId()).getOrderNums());
                hotProductVO.setProductNums(hotProductVO.getProductNums() + hotProductVOMap.get(merchantSpu.getSpuId()).getProductNums());
            }
            hotProductVO.setSpuName(supplierSpu.getSpuName());
            hotProductVO.setSpuImg(supplierSpu.getMainImgUrl());
            resultProdRankingList.add(hotProductVO);
        }
        List<HotProductVO> resultProdList = resultProdRankingList.stream().sorted(Comparator.comparing(HotProductVO::getPayAmount).reversed()).limit(limit).collect(Collectors.toList());
        resultProdList.forEach(item -> item.setPayAmount(Arith.div(item.getPayAmount(), 100, 2)));
        return resultProdList;
    }

    /**
     * 根据spuId列表， 获取spu列表信息
     *
     * @param spuIds 商品id列表
     * @return 商品列表
     */
    private List<SpuSearchVO> listSpuInfoByIds(List<Long> spuIds) {
        ServerResponseEntity<List<SpuSearchVO>> supplierSpuResponse = searchSpuFeignClient.listSpuBySpuIds(spuIds);
        if (supplierSpuResponse.isFail()) {
            throw new LuckException(supplierSpuResponse.getMsg());
        }
        List<SpuSearchVO> spuSearchVOList = supplierSpuResponse.getData();
        return spuSearchVOList;
    }

    /**
     * 根据店铺Id与时间范围获取订单概况信息
     *
     * @param supplierId
     * @param startTime
     * @param endTime
     * @return
     */
    private SupplierOrderOverviewVO getOrderStatisticsByShopIdAndDateRange(Long supplierId, Date startTime, Date endTime) {
        OrderOverviewVO todayOrderOverviewVO = mongoOrderManager.getOrderOverviewInfoBySupplierId(supplierId, startTime, endTime);
        OrderOverviewVO yesterdayOrderOverviewVO = mongoOrderManager.getOrderOverviewInfoBySupplierId(supplierId, DateUtil.offsetDay(startTime, -1), DateUtil.offsetDay(endTime, -1));
        OrderRefundStatisticsVO todayOrderRefundStatisticsVO = mongoOrderRefundManager.getOrderRefundInfoBySupplierId(supplierId, startTime, endTime);
        OrderRefundStatisticsVO yesterdayOrderRefundStatisticsVO = mongoOrderRefundManager.getOrderRefundInfoBySupplierId(supplierId, DateUtil.offsetDay(startTime, -1), DateUtil.offsetDay(endTime, -1));

        SupplierOrderOverviewVO supplierOrderOverviewVO = new SupplierOrderOverviewVO();
        supplierOrderOverviewVO.setTodayPayActual(todayOrderOverviewVO.getPayActual());
        supplierOrderOverviewVO.setYesterdayPayActual(yesterdayOrderOverviewVO.getPayActual());
        supplierOrderOverviewVO.setTodayPayUserCount(todayOrderOverviewVO.getPayUserCount());
        supplierOrderOverviewVO.setYesterdayPayUserCount(yesterdayOrderOverviewVO.getPayUserCount());
        supplierOrderOverviewVO.setTodayRefundAmount(todayOrderRefundStatisticsVO.getPayActualTotal());
        supplierOrderOverviewVO.setYesterdayRefundAmount(yesterdayOrderRefundStatisticsVO.getPayActualTotal());
        return supplierOrderOverviewVO;
    }

    /**
     * 根据供应商Id与时间范围按小时分段获取已出售商品数量列表
     *
     * @param supplierId
     * @param startTime
     * @param endTime
     */
    private List<Integer> listProdSoldCountByHour(Long supplierId, Date startTime, Date endTime) {
        List<SupplierOrderOverviewVO> supplierOrderOverviewVOList = mongoOrderManager.listProdSoldCountByHour(supplierId, startTime, endTime);
        Map<Integer, Integer> prodSoldCountMap = new HashMap<>(25);
        for (SupplierOrderOverviewVO supplierOrderOverviewVO : supplierOrderOverviewVOList) {
            prodSoldCountMap.put(Integer.parseInt(supplierOrderOverviewVO.getTimeData()) + 8, supplierOrderOverviewVO.getTodayProdSoldNums());
        }
        List<Integer> todayProdSoldCountList = new ArrayList<>();
        for (int i = 0; i < Constant.MAX_HOUR_NUM_BY_DAY; i++) {
            todayProdSoldCountList.add(prodSoldCountMap.getOrDefault(i, 0));
        }
        return todayProdSoldCountList;
    }


    /**
     * 根据店铺Id与时间范围按小时分段获取数据支付金额列表
     *
     * @param shopId
     * @param startTime
     * @param endTime
     */
//    private List<Double> getActualByHour(Long shopId, Date startTime, Date endTime) {
//        List<OrderOverviewVO> orderOverviewVOList = orderMapper.listActualByHour(shopId, startTime, endTime);
//        Map<Integer, Double> payMap = new HashMap<>(30);
//        for (OrderOverviewVO temp : orderOverviewVOList) {
//            payMap.put(Integer.parseInt(temp.getTimeData()), temp.getPayActual());
//        }
//        List<Double> nowActual = new ArrayList<>();
//        double sum = 0.00;
//        for (int i = 0; i < Constant.MAX_HOUR_NUM_BY_DAY; i++) {
//            if (payMap.get(i) != null) {
//                sum = Arith.add(sum, Arith.div(payMap.get(i), 100, 2));
//            }
//            nowActual.add(Arith.round(sum, 2));
//        }
//        return nowActual;
//    }

    /**
     * 根据店铺Id与时间范围按日期（以天为单位）分段获取数据支付金额列表
     *
     * @param supplierId
     * @param endTime
     * @param dayCount
     * @param supplierOrderOverviewVO
     */
    private void listPayActualAmount(Long supplierId, Date endTime, Integer dayCount, SupplierOrderOverviewVO supplierOrderOverviewVO) {
        Date startTime = this.getStartTime(endTime, dayCount);
        List<OrderOverviewVO> orderOverviewVOList = mongoOrderManager.listPayActualByDay(supplierId, startTime, endTime);
        Map<String, OrderOverviewVO> orderOverviewVOMap = orderOverviewVOList.stream().collect(Collectors.toMap(OrderOverviewVO::getTimeData, orderOverviewVO -> orderOverviewVO));

        List<Double> payActualList = new ArrayList<>();
        List<String> dateToStringList = new ArrayList<>();

        for (int i = 0; i < dayCount; i++) {
            if (orderOverviewVOMap.containsKey(DateUtils.dateToStrYmd(startTime))) {
                OrderOverviewVO orderOverviewVO = orderOverviewVOMap.get(DateUtils.dateToStrYmd(startTime));
                payActualList.add(Arith.div(orderOverviewVO.getPayActual(), 100, 2));
            } else {
                payActualList.add(0.0);
            }
            dateToStringList.add(DateUtils.dateToStrYmd(startTime));
            startTime = getNextTime(startTime);
        }

        supplierOrderOverviewVO.setDateToStringList(dateToStringList);
        supplierOrderOverviewVO.setPayActualList(payActualList);
    }


    /**
     * 根据结束时间与天数获取起始时间
     *
     * @param endTime
     * @param dayCount
     * @return
     */
    private Date getStartTime(Date endTime, Integer dayCount) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(endTime);
        calendar.add(Calendar.DATE, -dayCount + 1);
        return DateUtil.beginOfDay(calendar.getTime());
    }

    private Double getChangeRate(double nowValue, double oldValue) {
        if (Objects.equals(oldValue, 0.0)) {
            return Objects.equals(nowValue, 0.0) ? 0.0 : 1.0;
        }
        double minus = Arith.sub(nowValue, oldValue);
        return Arith.div(minus, oldValue, 4);
    }

    /**
     * 获取下一次循环的开始时间，以及设置后台显示的时间字符串
     *
     * @param startTime 开始时间
     * @return
     */
    private Date getNextTime(Date startTime) {
        startTime = DateUtil.offsetDay(startTime, 1);
        return startTime;
    }

    /**
     * 计算两个数的百分比
     *
     * @param dividend 被除数
     * @param divisor  除数
     * @return
     */
    private Double getRatioRate(Integer dividend, Integer divisor) {
        if (Objects.isNull(dividend) || dividend == 0.0) {
            return 0.0;
        }
        if (Objects.isNull(divisor) || divisor == 0.0) {
            return 100.0;
        }
        return Arith.mul(Arith.div(dividend, divisor, 4), 100.00);
    }
}
